import { IScope } from '../../../../types';
import { parseExpression } from '../../../expressionParser';
import { isLiteralAtomicExpr } from '../util/isLiteralAtomicExpr';
import { isSimpleStraightLiteral } from '../util/isSimpleStraightLiteral';
import { transformThis2Context } from './transformThis2Context';

export function transformJsExpr(
  expr: string,
  scope: IScope,
  {
    dontWrapEval = false,
    dontTransformThis2ContextAtRootScope = false,
    forceTransformThis = false,
    preserveThisForLoopVars = false,
  } = {},
) {
  if (!expr) {
    return 'undefined';
  }

  if (isLiteralAtomicExpr(expr)) {
    return expr;
  }

  // 处理循环变量引用，将this.item替换为item
  let processedExpr = expr;
  const bindings = scope.bindings?.getAllBindings() || [];

  // 检查是否包含作用域变量引用
  const hasScopeVars = bindings.length > 0 && !preserveThisForLoopVars;

  if (hasScopeVars) {
    // console.log('【transformJsExpr】处理作用域变量引用，原始表达式:', processedExpr);
    // console.log('【transformJsExpr】当前作用域变量:', bindings);

    bindings.forEach((binding) => {
      const pattern = new RegExp(`\\bthis\\.${binding}\\b`, 'g');
      if (pattern.test(processedExpr)) {
        // console.log(`【transformJsExpr】替换 this.${binding} 为 ${binding}`);
        processedExpr = processedExpr.replace(pattern, binding);
      }
    });

    // console.log('【transformJsExpr】处理后的表达式:', processedExpr);
  }

  // 尝试解析表达式
  let exprAst;
  try {
    exprAst = parseExpression(processedExpr);
  } catch (error) {
    // console.warn('解析表达式失败，返回原始表达式:', processedExpr, error);
    return processedExpr;
  }

  // 对于下面这些比较安全的字面值，可以直接返回对应的表达式，而非包一层
  if (isSimpleStraightLiteral(exprAst)) {
    return processedExpr;
  }

  if (dontWrapEval) {
    return transformThis2Context(exprAst, scope, {
      ignoreRootScope: dontTransformThis2ContextAtRootScope,
      forceTransform: forceTransformThis,
      preserveThisForLoopVars,
    });
  }

  switch (exprAst.type) {
    // 对于直接写个函数的，则不用再包下，因为这样不会抛出异常的
    case 'ArrowFunctionExpression':
    case 'FunctionExpression':
      return transformThis2Context(exprAst, scope, {
        ignoreRootScope: dontTransformThis2ContextAtRootScope,
        forceTransform: forceTransformThis,
        preserveThisForLoopVars,
      });

    default:
      break;
  }

  // 其他的都需要包一层
  return `__$$eval(() => (${transformThis2Context(exprAst, scope, {
    ignoreRootScope: dontTransformThis2ContextAtRootScope,
    forceTransform: forceTransformThis,
    preserveThisForLoopVars,
  })}))`;
}
